package com.github.caijh.mall.system.service.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import javax.annotation.Resource;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.caijh.commons.util.DesUtils;
import com.github.caijh.commons.util.Strings;
import com.github.caijh.framework.core.exception.BizException;
import com.github.caijh.mall.authorization.manager.TokenManager;
import com.github.caijh.mall.authorization.model.TokenModel;
import com.github.caijh.mall.common.PageParams;
import com.github.caijh.mall.constants.Constants;
import com.github.caijh.mall.exception.CrmebException;
import com.github.caijh.mall.system.dao.SystemAdminDao;
import com.github.caijh.mall.system.model.SystemAdmin;
import com.github.caijh.mall.system.model.SystemRole;
import com.github.caijh.mall.system.request.SystemAdminAddReqBody;
import com.github.caijh.mall.system.request.SystemAdminLoginReqBody;
import com.github.caijh.mall.system.request.SystemAdminReqBody;
import com.github.caijh.mall.system.request.SystemAdminRequest;
import com.github.caijh.mall.system.request.SystemAdminUpdateReqBody;
import com.github.caijh.mall.system.request.SystemRoleSearchRequest;
import com.github.caijh.mall.system.response.SystemAdminRespBody;
import com.github.caijh.mall.system.service.SystemAdminService;
import com.github.caijh.mall.system.service.SystemRoleService;
import com.github.caijh.mall.user.model.UserToken;
import com.github.caijh.mall.user.service.UserTokenService;
import com.github.caijh.mall.wechat.response.WeChatAuthorizeLoginGetOpenIdResponse;
import com.github.caijh.mall.wechat.service.WeChatService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import static com.github.pagehelper.page.PageMethod.startPage;

/**
 * SystemAdminServiceImpl 接口实现
 * +----------------------------------------------------------------------
 * | CRMEB [ CRMEB赋能开发者，助力企业发展 ]
 * +----------------------------------------------------------------------
 * | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
 * +----------------------------------------------------------------------
 * | Licensed CRMEB并不是自由软件，未经许可不能去掉CRMEB相关版权
 * +----------------------------------------------------------------------
 * | Author: CRMEB Team <admin@crmeb.com>
 * +----------------------------------------------------------------------
 */
@Service
public class SystemAdminServiceImpl extends ServiceImpl<SystemAdminDao, SystemAdmin> implements SystemAdminService {

    @Resource
    private SystemAdminDao dao;

    @Autowired
    private SystemRoleService systemRoleService;

    @Resource
    private TokenManager tokenManager;

    @Autowired
    private UserTokenService userTokenService;

    @Autowired
    private WeChatService weChatService;


    @Override
    public List<SystemAdminRespBody> getList(SystemAdminReqBody reqBody) {
        startPage(reqBody.getPage(), reqBody.getLimit());

        LambdaQueryWrapper<SystemAdmin> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        SystemAdmin systemAdmin = new SystemAdmin();
        BeanUtils.copyProperties(reqBody, systemAdmin);
        lambdaQueryWrapper.eq(StringUtils.isNotBlank(systemAdmin.getAccount()), SystemAdmin::getAccount, systemAdmin.getAccount());
        lambdaQueryWrapper.eq(null != systemAdmin.getId(), SystemAdmin::getId, systemAdmin.getId());
        lambdaQueryWrapper.eq(null != systemAdmin.getIsDel(), SystemAdmin::getIsDel, systemAdmin.getIsDel());
        lambdaQueryWrapper.eq(StringUtils.isNotBlank(systemAdmin.getLastIp()), SystemAdmin::getLastIp, systemAdmin.getLastIp());
        lambdaQueryWrapper.eq(null != systemAdmin.getLevel(), SystemAdmin::getLevel, systemAdmin.getLevel());
        lambdaQueryWrapper.eq(null != systemAdmin.getLoginCount(), SystemAdmin::getLoginCount, systemAdmin.getLoginCount());
        if (StringUtils.isNotBlank(systemAdmin.getRealName())) {
            lambdaQueryWrapper.like(SystemAdmin::getRealName, systemAdmin.getRealName());
            lambdaQueryWrapper.or().like(SystemAdmin::getAccount, systemAdmin.getRealName());
        }
        lambdaQueryWrapper.eq(StringUtils.isNotBlank(systemAdmin.getRoles()), SystemAdmin::getRoles, systemAdmin.getRoles());
        lambdaQueryWrapper.eq(null != systemAdmin.getStatus(), SystemAdmin::getStatus, systemAdmin.getStatus());
        List<SystemAdmin> systemAdmins = dao.selectList(lambdaQueryWrapper);
        List<SystemAdminRespBody> systemAdminRespList = new ArrayList<>();
        PageParams pageRole = new PageParams();
        pageRole.setLimit(999);
        List<SystemRole> roleList = systemRoleService.getList(new SystemRoleSearchRequest(), pageRole);
        for (SystemAdmin admin : systemAdmins) {
            SystemAdminRespBody sar = new SystemAdminRespBody();
            BeanUtils.copyProperties(admin, sar);
            sar.setLastTime(admin.getUpdateTime());
            if (StringUtils.isBlank(admin.getRoles())) continue;
            List<Integer> roleIds = Strings.toIntListByComma(admin.getRoles());
            List<String> roleNames = new ArrayList<>();
            for (Integer roleId : roleIds) {
                List<SystemRole> hasRoles = roleList.stream().filter(e -> e.getId().equals(roleId)).collect(Collectors.toList());
                if (!hasRoles.isEmpty()) {
                    roleNames.add(hasRoles.stream().map(SystemRole::getRoleName).collect(Collectors.joining(",")));
                }
            }
            sar.setRoleNames(StringUtils.join(roleNames, ","));
            systemAdminRespList.add(sar);
        }
        return systemAdminRespList;
    }

    @Override
    public SystemAdminRespBody login(SystemAdminLoginReqBody reqBody, String ip) {
        LambdaQueryWrapper<SystemAdmin> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(SystemAdmin::getAccount, reqBody.getAccount());
        SystemAdmin systemAdmin = dao.selectOne(lambdaQueryWrapper);

        validateUser(systemAdmin);

        String encryptPassword = DesUtils.getInstance().encrypt(reqBody.getPwd(), reqBody.getAccount());
        if (!systemAdmin.getPwd().equals(encryptPassword)) {
            throw BizException.of("USER_PASSWORD_ERROR");
        }
        return doLogin(ip, systemAdmin);
    }

    private SystemAdminRespBody doLogin(String ip, SystemAdmin systemAdmin) {
        TokenModel tokenModel = tokenManager.createToken(systemAdmin.getAccount(), systemAdmin.getId().toString(), Constants.ADMIN_USER_TOKEN_REDIS_KEY_PREFIX);
        SystemAdminRespBody systemAdminRespBody = new SystemAdminRespBody();
        systemAdminRespBody.setToken(tokenModel.getToken());
        BeanUtils.copyProperties(systemAdmin, systemAdminRespBody);

        //更新最后登录信息
        systemAdmin.setLoginCount(systemAdmin.getLoginCount() + 1);
        systemAdmin.setLastIp(ip);
        updateById(systemAdmin);

        return systemAdminRespBody;
    }

    private void validateUser(SystemAdmin systemAdmin) {
        if (null == systemAdmin) {
            throw BizException.of("USER_NOT_FOUND");
        }
        if (Boolean.FALSE.equals(systemAdmin.getStatus())) {
            throw BizException.of("USER_DISABLED");
        }
        if (Boolean.TRUE.equals(systemAdmin.getIsDel())) {
            throw BizException.of("USER_DELETED");
        }
    }

    @Override
    public Boolean logout(String token) {
        tokenManager.deleteToken(token, Constants.ADMIN_USER_TOKEN_REDIS_KEY_PREFIX);
        return true;
    }

    /**
     * 管理员详情
     *
     * @param request SystemAdminRequest
     * @return SystemAdminRespBody
     */
    @Override
    public SystemAdminRespBody getInfo(SystemAdminRequest request) {
        SystemAdmin systemAdmin = this.getById(request.getId());

        if (null == systemAdmin || systemAdmin.getId() < 0) {
            return null;
        }
        SystemAdminRespBody systemAdminRespBody = new SystemAdminRespBody();
        BeanUtils.copyProperties(systemAdmin, systemAdminRespBody);
        return systemAdminRespBody;
    }

    @Override
    public SystemAdminRespBody add(SystemAdminAddReqBody systemAdminAddReqBody) {
        try {
            // 管理员名称唯一校验
            Integer result = checkAccount(systemAdminAddReqBody.getAccount());
            if (result > 0) {
                throw new CrmebException("管理员已存在");
            }

            SystemAdmin systemAdmin = new SystemAdmin();
            BeanUtils.copyProperties(systemAdminAddReqBody, systemAdmin);

            // 执行新增管理员操作
            String pwd = DesUtils.getInstance().encrypt(systemAdmin.getPwd(), systemAdmin.getAccount());
            systemAdminAddReqBody.setPwd(pwd); // 设置为加密后的密码
            systemAdmin.setPwd(pwd);
            SystemAdminRespBody systemAdminRespBody = new SystemAdminRespBody();
            BeanUtils.copyProperties(systemAdminAddReqBody, systemAdminRespBody);
            if (dao.insert(systemAdmin) <= 0) {
                throw new CrmebException("新增管理员失败");
            }
            return systemAdminRespBody;

        } catch (Exception e) {
            throw new CrmebException("新增管理员异常 " + e.getMessage());
        }

    }

    private Integer checkAccount(String account) {
        LambdaQueryWrapper<SystemAdmin> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(SystemAdmin::getAccount, account);
        return dao.selectCount(lambdaQueryWrapper);

    }

    @Override
    public SystemAdminRespBody update(SystemAdminUpdateReqBody reqBody) {
        SystemAdmin systemAdmin = this.getById(reqBody.getId());
        if (null == systemAdmin) {
            throw new CrmebException("管理员不存在");
        }
        BeanUtils.copyProperties(reqBody, systemAdmin);
        if (null != reqBody.getPwd()) {
            String pwd = DesUtils.getInstance().encrypt(reqBody.getPwd(), reqBody.getAccount());
            systemAdmin.setPwd(pwd);
        }
        if (dao.updateById(systemAdmin) > 0) {
            SystemAdminRespBody systemAdminRespBody = new SystemAdminRespBody();
            BeanUtils.copyProperties(systemAdmin, systemAdminRespBody);
            return systemAdminRespBody;
        }
        throw new CrmebException("更新管理员异常");
    }

    @Override
    public SystemAdminRespBody getInfoByToken(String token) {
        boolean hasToken = tokenManager.checkToken(token, Constants.ADMIN_USER_TOKEN_REDIS_KEY_PREFIX);
        if (!hasToken) {
            throw new CrmebException("当前token无效");
        }
        TokenModel tokenModel = tokenManager.getToken(token, Constants.ADMIN_USER_TOKEN_REDIS_KEY_PREFIX);
        SystemAdminRequest systemAdminRequest = new SystemAdminRequest();
        systemAdminRequest.setId(tokenModel.getUserId());
        return getInfo(systemAdminRequest);
    }

    /**
     * 获取当前用户id
     *
     * @return Integer
     * @author Mr.Zhang
     * @since 2020-04-28
     */
    @Override
    public Integer getAdminId() {
        return Integer.parseInt(tokenManager.getLocalInfoException("id"));
    }

    /**
     * 获取当前用户信息
     *
     * @return SystemAdmin
     * @author Mr.Zhang
     * @since 2020-04-28
     */
    @Override
    public SystemAdmin getInfo() {
        return getInfo(getAdminId());
    }

    /**
     * 获取用户信息
     *
     * @return SystemAdmin
     * @author Mr.Zhang
     * @since 2020-04-28
     */
    @Override
    public SystemAdmin getInfo(Integer adminId) {
        return getById(adminId);
    }

    /**
     * 微信扫码登录
     *
     * @return SystemAdmin
     * @author Mr.Zhang
     * @since 2020-04-28
     */
    @Override
    public SystemAdminRespBody weChatAuthorizeLogin(String code, String ip) {
        //通过code获取用户信息
        WeChatAuthorizeLoginGetOpenIdResponse response = weChatService.authorizeLogin(code);
        UserToken userToken = userTokenService.getUserIdByOpenId(response.getOpenId(), Constants.THIRD_ADMIN_LOGIN_TOKEN_TYPE_PUBLIC);
        if (null == userToken) {
            throw new CrmebException("当前微信账号没有绑定后台账户，请用账号密码登录之后在个人中心扫码绑定");
        }

        SystemAdmin systemAdmin = getById(userToken.getUid());

        validateUser(systemAdmin);

        return doLogin(ip, systemAdmin);
    }

    /**
     * 绑定微信
     *
     * @return SystemAdmin
     * @author Mr.Zhang
     * @since 2020-04-28
     */
    public void bind(String code, Integer adminId) {
        try {
            //通过code获取用户信息
            WeChatAuthorizeLoginGetOpenIdResponse response = weChatService.authorizeLogin(code);
            UserToken userToken = userTokenService.checkToken(response.getOpenId(), Constants.THIRD_ADMIN_LOGIN_TOKEN_TYPE_PUBLIC);
            if (null == userToken) {
                userTokenService.bind(response.getOpenId(), Constants.THIRD_ADMIN_LOGIN_TOKEN_TYPE_PUBLIC, adminId);
            }
        } catch (Exception e) {
            throw new CrmebException("绑定失败：" + e.getMessage());
        }
    }

    /**
     * 修改后台管理员状态
     *
     * @param id
     * @param status
     * @return
     */
    @Override
    public boolean updateStatus(Integer id, Boolean status) {
        SystemAdmin systemAdmin = getById(id);
        if (ObjectUtil.isNull(systemAdmin)) {
            throw new CrmebException("用户不存在");
        }
        if (systemAdmin.getStatus().equals(status)) {
            return true;
        }
        systemAdmin.setStatus(status);
        return updateById(systemAdmin);
    }

    /**
     * 解绑微信
     *
     * @return Boolean
     * @author Mr.Zhang
     * @since 2020-04-28
     */
    @Override
    public Boolean unBind() {
        return userTokenService.unBind(Constants.THIRD_ADMIN_LOGIN_TOKEN_TYPE_PUBLIC, tokenManager.getLocalUserId());
    }

}

